<?php

namespace Core;

class Container
{
    protected $bindings = [];
    protected $instances = [];
    protected $aliases = [];
    protected static $instance;

    private function __construct()
    {
    }

    private function __clone()
    {
    }

    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function bind($abstract, $concrete = null, $shared = false)
    {
        if (is_null($concrete)) {
            $concrete = $abstract;
        }

        $this->bindings[$abstract] = [
            'concrete' => $concrete,
            'shared' => $shared
        ];
    }

    public function singleton($abstract, $concrete)
    {
        $this->bind($abstract, $concrete, true);
    }

    public function alias($abstract, $alias)
    {
        $this->aliases[$alias] = $abstract;
    }


    public function make($abstract, $parameters = [])
    {
        $abstract = $this->getAlias($abstract);

        if (!empty($this->instances[$abstract])) {
            return $this->instances[$abstract];
        }

        // 获取具体实例
        $concrete = $this->getConcrete($abstract);

        // 构建对象
        $object = $this->bulid($concrete, $parameters);

        // 如果是单例，保存实例
        if ($this->isShared($abstract)) {
            $this->instances[$abstract] = $object;
        }

        return $object;
    }

    public function bulid($concrete, $parameters)
    {
        // 如果是闭包，直接执行
        if ($concrete instanceof \Closure) {
            return $concrete($this, $parameters);
        }

        // 使用反射类分析依赖
        $reflector = new \ReflectionClass($concrete);

        // 检查类是否可实例化
        if (!$reflector->isInstantiable()) {
            throw new \Exception("Class {$concrete} is not instantiable");
        }

        // 获取构造函数
        $constructor = $reflector->getConstructor();

        // 如果没有构造函数，直接实例化
        if (is_null($constructor)) {
            return new $concrete;
        }

        // 获取构造函数参数
        $dependencies = $constructor->getParameters();

        // 解析依赖参数
        $instances = $this->resolveDependencies($dependencies, $parameters);

        // 创建实例
        return $reflector->newInstanceArgs($instances);
    }

    protected function resolveDependencies($dependencies, $parameters)
    {
        $results = [];

        foreach ($dependencies as $dependency) {
            // 如果有提供参数，使用参数
            if (isset($parameters[$dependency->name])) {
                $results[] = $parameters[$dependency->name];
                continue;
            }

            // 如果参数有类型提示，尝试解析类型
            if ($dependency->getType() && !$dependency->getType()->isBuiltin()) {
                $results[] = $this->make($dependency->getType()->getName());
                continue;
            }

            // 如果有默认值，使用默认值
            if ($dependency->isDefaultValueAvailable()) {
                $results[] = $dependency->getDefaultValue();
                continue;
            }

            // 无法解析依赖
            throw new \Exception("Unable to resolve dependency [{$dependency->name}]");
        }
        return $results;
    }

    public function getConcrete($abstract)
    {
        if (isset($this->bindings[$abstract])) {
            return $this->bindings[$abstract]['concrete'];
        }
        return $abstract;
    }

    protected function isShared($abstract)
    {
        return isset($this->bindings[$abstract]) && $this->bindings[$abstract]['shared'];
    }


    public function getAlias($alias)
    {
        return isset($this->aliases[$alias]) ? $this->aliases[$alias] : $alias;
    }

    // 注册实例
    public function instance($abstract, $instance)
    {
        $this->instances[$abstract] = $instance;
    }

    // 检查是否已绑定
    public function bound($abstract)
    {
        return isset($this->bindings[$abstract]) || isset($this->instances[$abstract]);
    }

    // 获取所有绑定
    public function getBindings()
    {
        return $this->bindings;
    }
}
